from typing import Optional
from fastapi import APIRouter, Request, Depends, Cookie, HTTPException
from fastapi.responses import HTMLResponse, FileResponse, RedirectResponse
from sqlalchemy.orm import Session
from database import get_db, SessionLocal
from models import Device
from utils import validate_session, get_mqtt_client
from core.logger import app_logger as logger
from datetime import datetime, timedelta
from templates import templates
from apscheduler.schedulers.background import BackgroundScheduler
import os
from apscheduler.schedulers import SchedulerAlreadyRunningError
import json
from paho.mqtt.client import MQTTMessage

router = APIRouter()                   

# MQTT配置
HEARTBEAT_TOPIC = "/board_ping"  # 心跳主题
mqtt_client = get_mqtt_client()  # 获取MQTT客户端

# 单例模式创建调度器
def get_scheduler():
    if not hasattr(get_scheduler, 'instance'):
        get_scheduler.instance = BackgroundScheduler()
    return get_scheduler.instance

scheduler = get_scheduler()

# MQTT消息回调函数
def on_mqtt_message(client, userdata, msg: MQTTMessage):
    try:
        # 解析MQTT心跳消息
        heart_data = json.loads(msg.payload.decode())
        # logger.info(f"接收到MQTT心跳")
        
        # 处理心跳数据
        db = SessionLocal()
        try:
            board_id = heart_data["BoardId"]
            instance = db.query(Device).filter(Device.BoardId == board_id).first()
            
            # 设备不存在则创建新记录
            if not instance:
                instance = Device(
                    BoardId=board_id,
                    Status='1',  # 默认在线
                    UpdateTime=datetime.now()
                )
                db.add(instance)
                logger.info(f"创建新设备记录: {board_id}")
            
            # 更新设备字段
            instance.BoardIp = heart_data.get("BoardIp", "")
            instance.BoardPlatform = heart_data.get("BoardPlatform", "")
            instance.BoardTemp = heart_data.get("BoardTemp", "")
            instance.BoardType = heart_data.get("BoardType", "")
            instance.GBClientId = heart_data.get("GBClientId", "")
            instance.GrantCode = str(heart_data.get("GrantCode", 0))
            instance.GrantDesc = heart_data.get("GrantDesc", "")
            
            # 磁盘信息处理
            host_disk = heart_data.get("HostDisk", {})
            instance.HostDiskAvailable = host_disk.get("Available", 0)
            instance.HostDiskTotal = host_disk.get("Total", 0)
            instance.HostDiskUsed = host_disk.get("Used", 0)
            
            # 内存信息处理
            host_memory = heart_data.get("HostMemory", [0, 0])
            instance.HostMemory0 = float(host_memory[0]) if len(host_memory) > 0 else 0.0
            instance.HostMemory1 = float(host_memory[1]) if len(host_memory) > 1 else 0.0
            
            instance.Key = heart_data.get("Key", "")
            instance.Status = '1'  # 收到心跳表示在线
            instance.UpdateTime = datetime.now()
            
            db.commit()
            # logger.info(f"设备状态更新成功: {board_id}")
        except Exception as e:
            db.rollback()
            logger.error(f"处理MQTT心跳失败: {str(e)}", exc_info=True)
        finally:
            db.close()
    except Exception as e:
        logger.error(f"MQTT消息处理异常: {str(e)}", exc_info=True)

# 启动时连接MQTT
@router.on_event("startup")
async def startup_event():
    try:
        # 初始化MQTT客户端
        if not mqtt_client.is_connected():
            mqtt_client.loop_start()
            mqtt_client.connect_async()
            logger.info("MQTT客户端启动")
        
        # 订阅心跳主题
        mqtt_client.subscribe(HEARTBEAT_TOPIC)
        mqtt_client.message_callback_add(HEARTBEAT_TOPIC, on_mqtt_message)
        logger.info(f"已订阅MQTT心跳主题: {HEARTBEAT_TOPIC}")
        
        # 启动调度器
        # init_device_scheduler(scheduler)
        # if not scheduler.running:
        #     scheduler.start()
        #     logger.info("调度器启动")
    except Exception as e:
        logger.error(f"启动失败: {str(e)}", exc_info=True)

# 关闭时清理资源
@router.on_event("shutdown")
async def shutdown_event():
    try:
        # 取消订阅
        mqtt_client.unsubscribe(HEARTBEAT_TOPIC)
        logger.info(f"已取消订阅MQTT主题: {HEARTBEAT_TOPIC}")
        
        # 停止调度器
        if scheduler.running:
            scheduler.shutdown()
            logger.info("调度器已关闭")
    except Exception as e:
        logger.error(f"关闭失败: {str(e)}", exc_info=True)

# 定时任务函数 - 检查设备状态
def check_device_status():
    now = datetime.now()
    db = SessionLocal()
    try:
        devices = db.query(Device).all()
        offline_count = 0
        for device in devices:
            # 新增逻辑：如果当前状态已经是离线(0)，不执行时间判断
            if device.Status != '0':  # 假设0表示离线，1表示在线,是char
                time_diff = now - device.UpdateTime
                if time_diff > timedelta(seconds=10):
                    device.Status = '0'  # 设置为离线 
                    offline_count += 1
        db.commit()
        logger.info(f"设备状态检查完成：共检查{len(devices)}台设备，{offline_count}台设备被标记为离线")
    except Exception as e:
        db.rollback()
        logger.error(f"设备状态更新失败: {str(e)}", exc_info=True)
    finally:
        db.close()

# 调度器启动函数
def init_device_scheduler(scheduler):
    """将设备检查任务添加到全局调度器"""
    scheduler.add_job(
        check_device_status,
        'interval',
        minutes=5,
        id='device_status_check'
    )

# 调度器关闭函数
def stop_scheduler():
    if scheduler.running:
        scheduler.shutdown()
        logger.info("APScheduler调度器已关闭")

@router.get("/devicemanage", response_class=HTMLResponse)
async def mange_page(
    request: Request,
    SessionId: Optional[str] = Cookie(None),
    UserName: Optional[str] = Cookie(None),
    db: Session = Depends(get_db)
):
    if not SessionId or not UserName or not validate_session(SessionId, UserName):
        return RedirectResponse(url="/")
    
    total_device_heartbeat = db.query(Device).count()
    device_heartbeat = db.query(Device).all()
    
    return templates.TemplateResponse("devicemanage.html", {
        "request": request,
        "UserName": UserName,
        "device_heartbeat": [heartbeat.to_dict() for heartbeat in device_heartbeat],
        "total_device_heartbeat": total_device_heartbeat
    })

@router.get("/api/devicemanage")
async def get_mange(
    db: Session = Depends(get_db), 
):
    device_heartbeat = db.query(Device).all()
    return {
        "status": "success", 
        "device_heartbeat": [heartbeat.to_dict() for heartbeat in device_heartbeat]
    }